JDK-4275210 : selectBestFlavor is not returning the same dataflavor every time
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.3.0
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,linux,solaris_2.5.1
  • CPU: generic,x86,sparc
  • Submitted: 1999-09-24
  • Updated: 2000-10-11
  • Resolved: 2000-09-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.0 betaFixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
DataFlavor.selectBestFlavor is not returning the same dataflavor every time when the same list of dataflavors are passed. 
When the order of DataFlavors in the list is changed the first encountered text  dataflavor is returned, so the best dataflavor is not the same always, even if the same list of dataflavors are passed each time. 
(for eg: dataflavor[] dfs1 = { DataFlavor.string, DataFlavor.plaintext, enrich} 
            dataflavor[] dfs2 = { enrich,DataFlavor.string,DataFlavor.plaintext} 

selectBestTextFlavor(dfs1) returns string flavor. 
selectBestTextFlavor(dfs2) returns enrich. 

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta FIXED IN: merlin-beta INTEGRATED IN: merlin-beta VERIFIED IN: merlin-beta
14-06-2004

SUGGESTED FIX ------- DataFlavor.java ------- *** /tmp/d0_Jn7_ Wed Aug 30 16:29:53 2000 --- DataFlavor.java Mon Aug 28 15:27:21 2000 *************** *** 13,18 **** --- 13,19 ---- import java.awt.Toolkit; import java.io.*; import java.util.*; + import sun.io.CharacterEncoding; import sun.awt.CharacterEncodingSupport; import sun.awt.DataTransferer; *************** *** 33,38 **** --- 34,80 ---- private static final long serialVersionUID = 8367026044764648243L; private static final Class ioInputStreamClass = java.io.InputStream.class; + + private static final Map preferredCharsets; + private static final Map textSubtypes; + + private static final int UNKNOWN_SUBTYPE = -1; + private static final int DEFAULT_CHARSET_INDEX = 10; + private static final String WORST_CHARSET = "ASCII"; + + static { + preferredCharsets = + Collections.synchronizedMap(new HashMap(4, 1.0f)); + textSubtypes = + Collections.synchronizedMap(new HashMap(13, 1.0f)); + + // plain text + textSubtypes.put("plain", new Integer(0)); + + // misc text subtypes + textSubtypes.put("calendar", new Integer(1)); + textSubtypes.put("css", new Integer(2)); + textSubtypes.put("directory", new Integer(3)); + textSubtypes.put("rfc822-headers", new Integer(4)); + textSubtypes.put("tab-separated-values", new Integer(5)); + textSubtypes.put("uri-list", new Integer(6)); + + // enriched subtypes + textSubtypes.put("richtext", new Integer(7)); + textSubtypes.put("enriched", new Integer(8)); + textSubtypes.put("rtf", new Integer(9)); + + // markup subtypes + textSubtypes.put("html", new Integer(10)); + textSubtypes.put("xml", new Integer(11)); + textSubtypes.put("sgml", new Integer(12)); + + // we prefer Unicode charsets + preferredCharsets.put("UTF16", new Integer(0)); + preferredCharsets.put("UTF8", new Integer(1)); + preferredCharsets.put("UnicodeBigUnmarked", new Integer(2)); + preferredCharsets.put("UnicodeLittleUnmarked", new Integer(3)); + } /** * Tries to load a class from: the bootstrap loader, the system loader, *************** *** 445,489 **** +"; class=java.io.InputStream", "Plain Text"); } // getTextPlainUnicodeFlavor() /** ! * Returns the best (highest fidelity) flavor in an encoding supported ! * by the JDK, or <code>null</code> if none can be found. * @param availableFlavors an array of available <code>DataFlavor</code>s ! * @return the best flavor */ public static final DataFlavor selectBestTextFlavor( ! DataFlavor[] availableFlavors) { ! if (availableFlavors == null) { ! return null; ! } ! DataFlavor selectedFlavor = null; ! for (int i = 0; ! (selectedFlavor == null) && (i < availableFlavors.length); ! ++i) { ! DataFlavor flavor = availableFlavors[i]; ! if (flavor.match(stringFlavor)) { ! // A serialized java.lang.String ! selectedFlavor = flavor; ! continue; ! } ! String primaryType = flavor.getPrimaryType(); ! if ((primaryType == null) || (!("text".equals(primaryType)))) { ! continue; ! } ! String charset = flavor.getParameter("charset"); ! if (charset == null) { ! // Take the platform default ! selectedFlavor = flavor; ! } else { ! if (DataTransferer.isEncodingSupported(charset)) { ! selectedFlavor = flavor; ! } ! } ! } ! //System.out.println("selectBestTextFlavor()->"+ selectedFlavor); ! return selectedFlavor; ! } // selectBestTextFlavor() /** * Gets a reader for an input stream, decoded for the expected * charset (encoding). This works only if the --- 487,627 ---- +"; class=java.io.InputStream", "Plain Text"); } // getTextPlainUnicodeFlavor() + private static int findStringIndex(Map strings, String string) { + Object index = strings.get(string); + if (index != null) { + return ((Integer)index).intValue(); + } + return UNKNOWN_SUBTYPE; + } + + /* + * It is assumed that passed charset names are canonical. + * Also, it is assumed that they aren't null. + * The rules of selecting best charset are described + * in selectBestTextFlavor(DataFlavor[] flavors). + */ + private static String selectBestCharset(String charset1, String charset2) { + + if (charset1.equals(WORST_CHARSET)) { + return charset2; + } else if (charset2.equals(WORST_CHARSET)) { + return charset1; + } + + int index1 = findStringIndex(preferredCharsets, charset1); + int index2 = findStringIndex(preferredCharsets, charset2); + if (charset1.equals(CharacterEncoding.aliasName( + DataTransferer.getDefaultTextCharset()))) { + index1 = DEFAULT_CHARSET_INDEX; // == 10 + } + if (charset2.equals(CharacterEncoding.aliasName( + DataTransferer.getDefaultTextCharset()))) { + index2 = DEFAULT_CHARSET_INDEX; // == 10 + } + + if (index1 == UNKNOWN_SUBTYPE) { + if (index2 == UNKNOWN_SUBTYPE && charset1.compareTo(charset2) <0){ + return charset1; + } + return charset2; + } + if (index2 == UNKNOWN_SUBTYPE) { + return charset1; + } + if (index1 < index2) { + return charset1; + } + return charset2; + } + /** ! * Selects the best text <code>DataFlavor</code> from an array of <code> ! * DataFlavor</code>s. Only <code>DataFlavor.stringFlavor</code>, and ! * equivalent flavors, and flavors that have a primary MIME type of "text", ! * are considered for selection. If the array contains <code>stringFlavor ! * </code>, or an equivalent flavor (a serialized <code>java.lang.String ! * </code>), then this flavor is selected. Flavors having "text" as their ! * primary MIME type are sorted by their secondary MIME type in the ! * following order: "plain", "calendar", "css", "directory", ! * "rfc822-header", "tab-separated-values", "uri-list", "richtext", ! * "enriched", "rtf", "html", "xml", "sgml". For example, "text/sgml" will ! * be selected over "text/html", and "text/enriched" will be selected over ! * "text/richtext". If there are two or more text flavors with the best MIME ! * subtype in the array, their charsets are compared. Unicode charsets, such ! * as "UTF-16", "UTF-8", "UTF-16BE" and "UTF-16LE", are considered best. ! * After them, platform default charset is selected. "US-ASCII" is worst. ! * All other charsets are chosen in alphabetical order. ! * * @param availableFlavors an array of available <code>DataFlavor</code>s ! * @return the best (highest fidelity) flavor in an encoding supported ! * by this implementation of the Java platform, or null if none can ! * be found. */ public static final DataFlavor selectBestTextFlavor( ! DataFlavor[] availableFlavors) { ! if (availableFlavors == null) { ! return null; ! } + DataFlavor selectedFlavor = null; + int selectedIndex = UNKNOWN_SUBTYPE; // == -1 + String selectedEncoding = + CharacterEncoding.aliasName(DataTransferer.getDefaultTextCharset()); + + for (int i = 0; i < availableFlavors.length; i++) { + + DataFlavor flavor = availableFlavors[i]; + + // Serialized String + if (flavor.match(stringFlavor)) { + selectedFlavor = flavor; + break; + } + + String primaryType = flavor.getPrimaryType(); + + if (primaryType == null || !"text".equals(primaryType)) { + continue; + } + + int stIndex = findStringIndex(textSubtypes, flavor.getSubType()); + + if (stIndex < selectedIndex || stIndex == UNKNOWN_SUBTYPE) { + continue; + } + + String charset = flavor.getParameter("charset"); + String currentEncoding; + + if (charset == null) { + currentEncoding = + CharacterEncoding.aliasName(DataTransferer.getDefaultTextCharset()); + } else { + if (!DataTransferer.isEncodingSupported(charset)) { + continue; + } + currentEncoding = CharacterEncoding.aliasName(charset); + } + + if (stIndex > selectedIndex) { + selectedFlavor = flavor; + selectedIndex = stIndex; + selectedEncoding = currentEncoding; + continue; + } + if (currentEncoding.equals(selectedEncoding) || + selectBestCharset(currentEncoding, selectedEncoding).equals(selectedEncoding)) { + continue; + } + + selectedFlavor = flavor; + selectedIndex = stIndex; + selectedEncoding = currentEncoding; + } + return selectedFlavor; + } + /** * Gets a reader for an input stream, decoded for the expected * charset (encoding). This works only if the
11-06-2004

EVALUATION We will not be able to fix this in Kestrel. Committing this bug to Merlin. eric.hawkes@eng 1999-11-08 We need consistent, deterministic behaviour for that method. Please see suggested fix: new javadoc comments for selectBestTextFlavor describe the algorithm.
08-11-1999