With Java 8 update101 HashMap.entries cannot be ca

2020-07-21 05:01发布

After updating to Java 8 update 101, I am getting exception in following code. It was working fine with Java 8 update 91.

Accessing keystore:

        KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
        ks.load(null, null);

        Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
        field.setAccessible(true);

        KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

        Collection entries;

        field = kss.getClass().getEnclosingClass().getDeclaredField("entries");
        field.setAccessible(true);

        // This is where the exception happens
        entries = (Collection) field.get(kss);

        // I then have to loop on these entries, something like this:

        for (Object entry : entries) { //code }

Type casting, exception is thrown:

java.util.HashMap cannot be cast to java.util.Collection

Any recent changes in Java 8 update 101? How to solve it?

标签: java java-8
4条回答
萌系小妹纸
2楼-- · 2020-07-21 05:37

Before Java 8u101, you needed to access this private field to work around bug http://bugs.openjdk.java.net/browse/JDK-6483657. This bug has been fixed in Java 8u101, so you can go back to using the official keystore API.

查看更多
Ridiculous、
3楼-- · 2020-07-21 05:46

The following change will make it work with 8u101, but it does not take away the fact that you are messing with the internals of class KeyStore which you should really not mess with.

The problem is that some object changed from being a Collection to being a HashMap in Java 8u101, and a HashMap is not a Collection, so trying to cast it to Collection causes a ClassCastException.

KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
ks.load(null, null);

Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
field.setAccessible(true);

KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

Collection entries;

field =kss.getClass().getEnclosingClass().getDeclaredField("entries");
field.setAccessible(true);
entries = (HashMap)field.get(kss);

for (Map.Entry entry : entries) {
    Object key = entry.getKey();
    Object value = entry.getValue();
    System.out.println(key + " = " + value);
}
查看更多
家丑人穷心不美
4楼-- · 2020-07-21 05:50

I confirm it does not work using the following as test code

import java.util.HashMap;
import java.util.Collection;

public class HelloWorld {
   public static void main(String[] args) {
      HashMap map = new HashMap();
      Collection c;
      c = (Collection) map;
   }
}

The outcome is Exception in thread "main" java.lang.ClassCastException: java.util.HashMap cannot be cast to java.util.Collection at HelloWorld.main(HelloWorld.java:8)

You can override it by using the values() method like this

import java.util.HashMap;
import java.util.Collection;

public class HelloWorld {
   public static void main(String[] args) {
      HashMap map = new HashMap();
      Collection c;
      c = map.values();
   }
}

So your code should be like this

import java.util.HashMap;
import java.util.Collection;
import java.security.*;
import java.lang.reflect.Field;

public class HelloWorld {
   public static void main(String[] args) {
    try{
      KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
        ks.load(null, null);

        Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
        field.setAccessible(true);

        KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

        Collection entries;

        field =kss.getClass().getEnclosingClass().getDeclaredField("entries");
        field.setAccessible(true);
        entries = ((HashMap) field.get(kss)).values();
    }catch(Exception e){
        e.printStackTrace();
    }
   }
}
查看更多
乱世女痞
5楼-- · 2020-07-21 05:55

How to solve it?

As pointed out in the comments, what you are doing is nasty. You should not be messing around with the internal implementation details of library classes. They are liable to change, and your code will then break ... as it has done here.

The best solution is to restrict yourself to using the public API methods for KeyStore; for example, call aliases() and then iterate the resulting Enumeration<String> looking up the entries for each alias.

If you can't do that, then you will need to modify your code to work with all of the different implementations of KeyStore that you and other users of your code might encounter.

查看更多
登录 后发表回答