<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Hi<br>
    <br>
    This has not been asked for and there is also no bug yet but
    nevertheless let me propose to change Attributes.map to specific
    generic types. It looks like the type parameters were added
    automatically with their introduction in java 5. I figure that no
    specific test is required in this particular case because it's a
    pure compile-time issue which is already sufficiently covered with
    existing code and there are also tests that already now involve
    manifests with attributes at run-time.<br>
    <br>
    Any feedback or thoughts? Would someone volunteer to sponsor it?<br>
    <br>
    Regards,<br>
    Philipp<br>
    <br>
    <br>
    <br>
    ----- BEGIN PATCH -----<br>
    diff -r 2e947e1bd907
    src/java.base/share/classes/java/util/jar/Attributes.java<br>
    --- a/src/java.base/share/classes/java/util/jar/Attributes.java   
    Mon Oct 02 10:04:22 2017 -0700<br>
    +++ b/src/java.base/share/classes/java/util/jar/Attributes.java   
    Tue Oct 03 07:41:40 2017 +0200<br>
    @@ -1,5 +1,5 @@<br>
     /*<br>
    - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All
    rights reserved.<br>
    + * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All
    rights reserved.<br>
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.<br>
      *<br>
      * This code is free software; you can redistribute it and/or
    modify it<br>
    @@ -54,11 +54,11 @@<br>
      * @see     Manifest<br>
      * @since   1.2<br>
      */<br>
    -public class Attributes implements Map<Object,Object>,
    Cloneable {<br>
    +public class Attributes implements Map<Attributes.Name,
    String>, Cloneable {<br>
         /**<br>
          * The attribute name-value mappings.<br>
          */<br>
    -    protected Map<Object,Object> map;<br>
    +    protected Map<Name, String> map;<br>
     <br>
         /**<br>
          * Constructs a new, empty Attributes object with default size.<br>
    @@ -87,7 +87,6 @@<br>
             map = new LinkedHashMap<>(attr);<br>
         }<br>
     <br>
    -<br>
         /**<br>
          * Returns the value of the specified attribute name, or null
    if the<br>
          * attribute name was not found.<br>
    @@ -96,7 +95,7 @@<br>
          * @return the value of the specified attribute name, or null
    if<br>
          *         not found.<br>
          */<br>
    -    public Object get(Object name) {<br>
    +    public String get(Object name) {<br>
             return map.get(name);<br>
         }<br>
     <br>
    @@ -116,7 +115,7 @@<br>
          * @throws IllegalArgumentException if the attribute name is
    invalid<br>
          */<br>
         public String getValue(String name) {<br>
    -        return (String)get(new Attributes.Name(name));<br>
    +        return get(new Attributes.Name(name));<br>
         }<br>
     <br>
         /**<br>
    @@ -133,7 +132,7 @@<br>
          *         not found.<br>
          */<br>
         public String getValue(Name name) {<br>
    -        return (String)get(name);<br>
    +        return get(name);<br>
         }<br>
     <br>
         /**<br>
    @@ -144,11 +143,9 @@<br>
          * @param name the attribute name<br>
          * @param value the attribute value<br>
          * @return the previous value of the attribute, or null if none<br>
    -     * @exception ClassCastException if the name is not a
    Attributes.Name<br>
    -     *            or the value is not a String<br>
          */<br>
    -    public Object put(Object name, Object value) {<br>
    -        return map.put((Attributes.Name)name, (String)value);<br>
    +    public String put(Attributes.Name name, String value) {<br>
    +        return map.put(name, value);<br>
         }<br>
     <br>
         /**<br>
    @@ -168,7 +165,7 @@<br>
          * @exception IllegalArgumentException if the attribute name is
    invalid<br>
          */<br>
         public String putValue(String name, String value) {<br>
    -        return (String)put(new Name(name), value);<br>
    +        return put(new Name(name), value);<br>
         }<br>
     <br>
         /**<br>
    @@ -178,7 +175,7 @@<br>
          * @param name attribute name<br>
          * @return the previous value of the attribute, or null if none<br>
          */<br>
    -    public Object remove(Object name) {<br>
    +    public String remove(Object name) {<br>
             return map.remove(name);<br>
         }<br>
     <br>
    @@ -208,15 +205,14 @@<br>
          * Copies all of the attribute name-value mappings from the
    specified<br>
          * Attributes to this Map. Duplicate mappings will be replaced.<br>
          *<br>
    -     * @param attr the Attributes to be stored in this map<br>
    -     * @exception ClassCastException if attr is not an Attributes<br>
    +     * @param attr the attributes to be stored in this map, may
    also be of<br>
    +     *             type {@link Attributes}<br>
          */<br>
    -    public void putAll(Map<?,?> attr) {<br>
    -        // ## javac bug?<br>
    -        if (!Attributes.class.isInstance(attr))<br>
    -            throw new ClassCastException();<br>
    -        for (Map.Entry<?,?> me : (attr).entrySet())<br>
    +    public void putAll(Map<? extends Name, ? extends String>
    attr) {<br>
    +        for (Map.Entry<? extends Name, ? extends String> me<br>
    +                : attr.entrySet()) {<br>
                 put(me.getKey(), me.getValue());<br>
    +        }<br>
         }<br>
     <br>
         /**<br>
    @@ -243,14 +239,14 @@<br>
         /**<br>
          * Returns a Set view of the attribute names (keys) contained
    in this Map.<br>
          */<br>
    -    public Set<Object> keySet() {<br>
    +    public Set<Name> keySet() {<br>
             return map.keySet();<br>
         }<br>
     <br>
         /**<br>
          * Returns a Collection view of the attribute values contained
    in this Map.<br>
          */<br>
    -    public Collection<Object> values() {<br>
    +    public Collection<String> values() {<br>
             return map.values();<br>
         }<br>
     <br>
    @@ -258,7 +254,7 @@<br>
          * Returns a Collection view of the attribute name-value
    mappings<br>
          * contained in this Map.<br>
          */<br>
    -    public Set<Map.Entry<Object,Object>> entrySet() {<br>
    +    public Set<Map.Entry<Name, String>> entrySet() {<br>
             return map.entrySet();<br>
         }<br>
     <br>
    @@ -290,7 +286,7 @@<br>
          * the Attributes returned can be safely modified without
    affecting<br>
          * the original.<br>
          */<br>
    -    public Object clone() {<br>
    +    public Attributes clone() {<br>
             return new Attributes(this);<br>
         }<br>
     <br>
    @@ -300,12 +296,12 @@<br>
          */<br>
          @SuppressWarnings("deprecation")<br>
          void write(DataOutputStream os) throws IOException {<br>
    -         for (Entry<Object, Object> e : entrySet()) {<br>
    +         for (Entry<Name, String> e : entrySet()) {<br>
                  StringBuffer buffer = new StringBuffer(<br>
    -                                         ((Name)
    e.getKey()).toString());<br>
    +                 e.getKey().toString());<br>
                  buffer.append(": ");<br>
     <br>
    -             String value = (String) e.getValue();<br>
    +             String value = e.getValue();<br>
                  if (value != null) {<br>
                      byte[] vb = value.getBytes("UTF8");<br>
                      value = new String(vb, 0, 0, vb.length);<br>
    @@ -343,14 +339,14 @@<br>
     <br>
             // write out all attributes except for the version<br>
             // we wrote out earlier<br>
    -        for (Entry<Object, Object> e : entrySet()) {<br>
    -            String name = ((Name) e.getKey()).toString();<br>
    +        for (Entry<Name, String> e : entrySet()) {<br>
    +            String name = e.getKey().toString();<br>
                 if ((version != null) &&
    !(name.equalsIgnoreCase(vername))) {<br>
     <br>
                     StringBuffer buffer = new StringBuffer(name);<br>
                     buffer.append(": ");<br>
     <br>
    -                String value = (String) e.getValue();<br>
    +                String value = e.getValue();<br>
                     if (value != null) {<br>
                         byte[] vb = value.getBytes("UTF8");<br>
                         value = new String(vb, 0, 0, vb.length);<br>
    diff -r 2e947e1bd907
    src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java<br>
    ---
a/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java   
    Mon Oct 02 10:04:22 2017 -0700<br>
    +++
b/src/java.base/share/classes/sun/net/www/protocol/jar/URLJarFile.java   
    Tue Oct 03 07:41:40 2017 +0200<br>
    @@ -1,5 +1,5 @@<br>
     /*<br>
    - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All
    rights reserved.<br>
    + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All
    rights reserved.<br>
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.<br>
      *<br>
      * This code is free software; you can redistribute it and/or
    modify it<br>
    @@ -148,14 +148,14 @@<br>
     <br>
             Manifest man = new Manifest();<br>
             Attributes attr = man.getMainAttributes();<br>
    -        attr.putAll((Map)superAttr.clone());<br>
    +        attr.putAll(superAttr.clone());<br>
     <br>
             // now deep copy the manifest entries<br>
             if (superEntries != null) {<br>
                 Map<String, Attributes> entries =
    man.getEntries();<br>
                 for (String key : superEntries.keySet()) {<br>
                     Attributes at = superEntries.get(key);<br>
    -                entries.put(key, (Attributes) at.clone());<br>
    +                entries.put(key, at.clone());<br>
                 }<br>
             }<br>
     <br>
    @@ -261,7 +261,7 @@<br>
                     if (e != null) {<br>
                         Attributes a = e.get(getName());<br>
                         if (a != null)<br>
    -                        return  (Attributes)a.clone();<br>
    +                        return a.clone();<br>
                     }<br>
                 }<br>
                 return null;<br>
    diff -r 2e947e1bd907
    src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java<br>
    ---
a/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java   
    Mon Oct 02 10:04:22 2017 -0700<br>
    +++
b/src/java.base/share/classes/sun/security/util/ManifestEntryVerifier.java   
    Tue Oct 03 07:41:40 2017 +0200<br>
    @@ -30,6 +30,7 @@<br>
     import java.security.CodeSigner;<br>
     import java.util.*;<br>
     import java.util.jar.*;<br>
    +import java.util.jar.Attributes.Name;<br>
     <br>
     import java.util.Base64;<br>
     <br>
    @@ -122,7 +123,7 @@<br>
                 }<br>
             }<br>
     <br>
    -        for (Map.Entry<Object,Object> se : attr.entrySet()) {<br>
    +        for (Map.Entry<Name, String> se : attr.entrySet()) {<br>
                 String key = se.getKey().toString();<br>
     <br>
                 if
    (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {<br>
    @@ -146,7 +147,7 @@<br>
                         digest.reset();<br>
                         digests.add(digest);<br>
                         manifestHashes.add(<br>
    -                               
    Base64.getMimeDecoder().decode((String)se.getValue()));<br>
    +                               
    Base64.getMimeDecoder().decode(se.getValue()));<br>
                     }<br>
                 }<br>
             }<br>
    diff -r 2e947e1bd907
    src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java<br>
    ---
a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java   
    Mon Oct 02 10:04:22 2017 -0700<br>
    +++
b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java   
    Tue Oct 03 07:41:40 2017 +0200<br>
    @@ -46,6 +46,7 @@<br>
     import java.util.Locale;<br>
     import java.util.Map;<br>
     import java.util.jar.Attributes;<br>
    +import java.util.jar.Attributes.Name;<br>
     import java.util.jar.JarException;<br>
     import java.util.jar.JarFile;<br>
     import java.util.jar.Manifest;<br>
    @@ -445,7 +446,7 @@<br>
             boolean validEntry = false;<br>
     <br>
             // go through all the attributes and process
    *-Digest-Manifest entries<br>
    -        for (Map.Entry<Object,Object> se : mattr.entrySet())
    {<br>
    +        for (Map.Entry<Name, String> se : mattr.entrySet()) {<br>
     <br>
                 String key = se.getKey().toString();<br>
     <br>
    @@ -469,7 +470,7 @@<br>
                     if (digest != null) {<br>
                         byte[] computedHash =
    md.manifestDigest(digest);<br>
                         byte[] expectedHash =<br>
    -                       
    Base64.getMimeDecoder().decode((String)se.getValue());<br>
    +                       
    Base64.getMimeDecoder().decode(se.getValue());<br>
     <br>
                         if (debug != null) {<br>
                             debug.println("Signature File: Manifest
    digest " +<br>
    @@ -517,7 +518,7 @@<br>
     <br>
             // go through all the attributes and process<br>
             // digest entries for the manifest main attributes<br>
    -        for (Map.Entry<Object,Object> se : mattr.entrySet())
    {<br>
    +        for (Map.Entry<Name, String> se : mattr.entrySet()) {<br>
                 String key = se.getKey().toString();<br>
     <br>
                 if
    (key.toUpperCase(Locale.ENGLISH).endsWith(ATTR_DIGEST)) {<br>
    @@ -540,7 +541,7 @@<br>
                             md.get(ManifestDigester.MF_MAIN_ATTRS,
    false);<br>
                         byte[] computedHash = mde.digest(digest);<br>
                         byte[] expectedHash =<br>
    -                       
    Base64.getMimeDecoder().decode((String)se.getValue());<br>
    +                       
    Base64.getMimeDecoder().decode(se.getValue());<br>
     <br>
                         if (debug != null) {<br>
                          debug.println("Signature File: " +<br>
    @@ -620,7 +621,7 @@<br>
                 //hex.encodeBuffer(data, System.out);<br>
     <br>
                 // go through all the attributes and process *-Digest
    entries<br>
    -            for (Map.Entry<Object,Object> se :
    sfAttr.entrySet()) {<br>
    +            for (Map.Entry<Name, String> se :
    sfAttr.entrySet()) {<br>
                     String key = se.getKey().toString();<br>
     <br>
                     if
    (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {<br>
    @@ -643,7 +644,7 @@<br>
                             boolean ok = false;<br>
     <br>
                             byte[] expected =<br>
    -                           
    Base64.getMimeDecoder().decode((String)se.getValue());<br>
    +                           
    Base64.getMimeDecoder().decode(se.getValue());<br>
                             byte[] computed;<br>
                             if (workaround) {<br>
                                 computed =
    mde.digestWorkaround(digest);<br>
    diff -r 2e947e1bd907
    src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java<br>
    ---
    a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java   
    Mon Oct 02 10:04:22 2017 -0700<br>
    +++
    b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java   
    Tue Oct 03 07:41:40 2017 +0200<br>
    @@ -685,7 +685,7 @@<br>
                 // Manifest exists. Read its raw bytes.<br>
                 mfRawBytes =
    zipFile.getInputStream(mfFile).readAllBytes();<br>
                 manifest.read(new ByteArrayInputStream(mfRawBytes));<br>
    -            oldAttr = (Attributes)
    (manifest.getMainAttributes().clone());<br>
    +            oldAttr = manifest.getMainAttributes().clone();<br>
             } else {<br>
                 // Create new manifest<br>
                 Attributes mattr = manifest.getMainAttributes();<br>
    ----- END PATCH -----<br>
    <div class="moz-signature"> <br>
      <br>
      <hr size="2" width="100%"><br>
      <img shrinktofit="true"
        src="cid:part1.E772C18D.0096E6E2@paratix.ch" align="bottom"
        border="0"><br>
      <br>
      Paratix GmbH<br>
      St Peterhofstatt 11<br>
      8001 Zürich<br>
      <br>
      +41 (0)76 397 79 35<br>
      <a href="mailto:philipp.kunz@paratix.ch">philipp.kunz@paratix.ch</a>
    </div>
  </body>
</html>